package com.heima.schedule.service.impl;


import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.redisClient.RedisCacheService;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.schedule.pojos.Taskinfo;
import com.heima.model.schedule.pojos.TaskinfoLogs;
import com.heima.schedule.constants.ScheduleConstants;
import com.heima.schedule.mapper.TaskinfoLogsMapper;
import com.heima.schedule.mapper.TaskinfoMapper;
import com.heima.schedule.service.TaskService;
import io.lettuce.core.models.role.RedisSentinelInstance;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author 张一恒
 * @version 1.0
 * @description:
 * @date 2023/1/16 21:05
 */
@Service
@Slf4j
public class TaskServiceImpl implements TaskService {


    @Autowired
    private TaskinfoMapper taskinfoMapper;

    @Autowired
    private TaskinfoLogsMapper taskinfoLogsMapper;

    @Autowired
    private RedisCacheService redisCacheService;

    @Autowired
    private TaskService taskService;

    /**
     * 添加任务
     *
     * @param task 任务对象
     * @return 任务id
     */
    @Override
    public Long addTask(Task task) {
        if (task == null) {
            log.debug("无定时发布请求");
            return null;
        }

        //数据保存到数据库
        Boolean addDbResult = taskService.addTaskSendDb(task);
        if (!addDbResult) {
            return null;
        }

        //保存到redis
        addTaskSendRedis(task);
        return task.getTaskId();
    }


    //保存任务到redis
    private void addTaskSendRedis(Task task) {

        String key = task.getTaskType() + "_" + task.getPriority();

        //根据时间判断，小与当前时间的存入list数据类型中 代表直接被消费
        if (task.getExecuteTime() <= System.currentTimeMillis()) {
            redisCacheService.lLeftPush(ScheduleConstants.TOPIC + key, JSON.toJSONString(task));
        }

        //大于当前时间且小于等于当前时间五分钟之后的存到zset中 代表未来数据队列

        //获取当前时间五分钟后的时间戳
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, 5);
        long fiveTime = c.getTimeInMillis();

        if (task.getExecuteTime() > System.currentTimeMillis() && task.getExecuteTime() <= fiveTime) {
            redisCacheService.zAdd(ScheduleConstants.FUTURE + key, JSON.toJSONString(task), task.getExecuteTime());
        }

    }


    //任务数据保存到数据库
    @Transactional
    @Override
    public Boolean addTaskSendDb(Task task) {

        //保存到任务表
        try {
            Taskinfo taskinfo = new Taskinfo();
            taskinfo.setExecuteTime(new Date(task.getExecuteTime()));
            taskinfo.setParameters(task.getParameters());
            taskinfo.setPriority(task.getPriority());
            taskinfo.setTaskType(task.getTaskType());
            taskinfoMapper.insert(taskinfo);

            task.setTaskId(taskinfo.getTaskId());
            //保存到任务日志表
            TaskinfoLogs taskinfoLogs = new TaskinfoLogs();
            taskinfoLogs.setTaskId(taskinfo.getTaskId());
            taskinfoLogs.setExecuteTime(taskinfo.getExecuteTime());
            taskinfoLogs.setParameters(taskinfo.getParameters());
            taskinfoLogs.setPriority(taskinfo.getPriority());
            taskinfoLogs.setTaskType(taskinfo.getTaskType());
            taskinfoLogs.setVersion(ScheduleConstants.VERSION); //初始化乐观锁状态
            taskinfoLogs.setStatus(ScheduleConstants.SCHEDULED); //0 初始状态
            taskinfoLogsMapper.insert(taskinfoLogs);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("时发布任务保存到db失败:{}", e.getMessage());
            return false;
        }
    }


    /**
     * @param taskType
     * @param priority
     * @return void
     * @description 拉取redis里的消费数据 删除任务表数据修改任务日志表状态
     * @author 31115
     * @date 2023/1/16 23:05
     */
    @Override
    @Transactional
    public void pullTaskDb(Integer taskType, Integer priority) {
        String key = ScheduleConstants.TOPIC + taskType + "_" + priority;
        //移除并获取元素
        List<String> consumptionData = redisCacheService.lRange(key, 0, -1);
        redisCacheService.delete(key);

        List<Task> tasks = new ArrayList<>();
        if (consumptionData.size()>0){
            for (String consumptionDatum : consumptionData) {
                Task task = JSON.parseObject(consumptionDatum, Task.class);
                tasks.add(task);
            }
        }

        if (tasks.size() > 0) {
            for (Task task : tasks) {
                //删除任务表数据
                taskinfoMapper.deleteById(task.getTaskId());

                //修改任务日志表状态
                TaskinfoLogs taskinfoLogs = taskinfoLogsMapper.selectById(task.getTaskId());
                taskinfoLogs.setStatus(ScheduleConstants.EXECUTED);
                taskinfoLogsMapper.updateById(taskinfoLogs);
//                taskinfoLogsMapper.update(taskinfoLogs,
//                        Wrappers.<TaskinfoLogs>lambdaUpdate().eq(TaskinfoLogs::getTaskId, task.getTaskId()));
            }
        }
    }
}
